package handler

import (
	"CodeCover/internal/log"
	"CodeCover/internal/models"
	"CodeCover/internal/service"
	"CodeCover/internal/service/cover"
	"CodeCover/internal/utils"

	"net/http"
	"path/filepath"
	"strconv"

	"github.com/gin-gonic/gin"
	"github.com/google/uuid"
)

type ExecuteHandler struct {
	taskService *service.TaskService
	userService *service.UserService
	gitService  *service.GitService
}

func NewExecuteHandler(tSvc *service.TaskService, uSvc *service.UserService, gSvc *service.GitService) *ExecuteHandler {
	return &ExecuteHandler{taskService: tSvc, userService: uSvc, gitService: gSvc}
}

func (h *ExecuteHandler) GetRq(ctx *gin.Context) {
	// 处理表单绑定
	var t models.Task
	if err := ctx.Bind(&t); err != nil {
		ctx.JSON(http.StatusBadRequest, gin.H{"error": "invalid request"})
		return
	}

	token := ctx.PostForm("token")
	if !h.userService.IsValidToken(ctx.Request.Context(), t.UserName, token) {
		ctx.JSON(http.StatusBadRequest, gin.H{"error": "invalid token"})
		return
	}

	// 获取用户uid
	uid, err := h.userService.GetUidByName(ctx.Request.Context(), t.UserName)
	if err != nil {
		ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	t.Uid = uid

	// 生成任务tid
	t.Tid = uuid.New().String()
	// 1. 写入任务元数据
	if err := h.taskService.Create(ctx.Request.Context(), &t); err != nil {
		ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	// 2. 拉取代码
	err = h.gitService.Clone(t.RepoUrl, t.Branch, t.Uid, t.Tid)
	if err != nil {
		ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	taskDir := filepath.Join(h.gitService.LoadPath(), strconv.FormatUint(t.Uid, 10), t.Tid)
	if err := h.taskService.UpdatePathByTid(ctx.Request.Context(), t.Tid, taskDir); err != nil {
		log.Logger.Errorf("UpdatePathByTid falied: %v", err)
		ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	// 3. go test -> coverage.out
	repoDir := filepath.Join(h.gitService.LoadPath(), strconv.FormatUint(t.Uid, 10), t.Tid, utils.RepoName(t.RepoUrl))

	if err = utils.RunCommandInDir(ctx.Request.Context(), repoDir, "go", "test", "-coverprofile=coverage.out", "./..."); err != nil {
		log.Logger.Errorf("RunCommandInDir falied: %v, cmdDir=%s", err, repoDir)
		ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	if err = cover.AppendTestFilesToCoverage(repoDir, "coverage.out"); err != nil {
		log.Logger.Errorf("AppendTestFilesToCoverage falied: %v, cmdDir=%s", err, repoDir)
		ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	// 4. 分析覆盖率文件，写入html DIR
	err = cover.GoHtmlOutput(filepath.Join(repoDir, "coverage.out"))
	if err != nil {
		ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	// 5. 计算平均覆盖率
	total, covered, percent := cover.TotalAvePercent(repoDir)
	h.taskService.UpdatePercentById(ctx.Request.Context(), t.Tid, total, covered, percent)

	ctx.JSON(http.StatusOK, gin.H{"message": "parse and generate html success"})
}
